package com.luban.spring;

import com.luban.demo.BeanDefinition;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 充当容器 类
 */
public class LuBanApplicationContext {

    private Class appConfigClass;

    //BeanDefinitionMap
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

    //单例池
    private Map<String, Object> singletonObjectsMap = new ConcurrentHashMap<String, Object>();

    public LuBanApplicationContext(Class appConfigClass) throws Exception {
        this.appConfigClass = appConfigClass;

        //拿到扫描到的class
        List<Class> classList = scan(appConfigClass);

        //过滤  去掉那些没有加Component注解的类
        for (Class clazz : classList) {
            if(clazz.isAnnotationPresent(Component.class)){
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanClass(clazz);
                //获取BeanName
                Component annotation = (Component) clazz.getAnnotation(Component.class);
                String beanName = annotation.value();
                if(beanName.equals("")){
                    beanName = clazz.getSimpleName().toLowerCase();
                }
                if(clazz.isAnnotationPresent(Scope.class)){
                    //获取Scope信息
                    Scope scopeAnnotation = (Scope)clazz.getAnnotation(Scope.class);
                    String scope = scopeAnnotation.value();
                    beanDefinition.setScope(scope);
                }else {
                    //单例
                    beanDefinition.setScope("singleton");
                }
                beanDefinitionMap.put(beanName,beanDefinition);
            }
        }
        
        //基于class去创建实例
        instanceSingletonBean();
    }

    /**
     * 扫描类
     * @param appConfigClass
     * @throws UnsupportedEncodingException
     * @throws ClassNotFoundException
     */
    private List<Class> scan(Class appConfigClass) throws UnsupportedEncodingException, ClassNotFoundException {
        List<Class> classList = new ArrayList<Class>();

        //扫描 得到Class
        //1.得到扫描路径
        ComponentScan componentScanAnnotation = (ComponentScan) appConfigClass.getAnnotation(ComponentScan.class);
        String path = componentScanAnnotation.value();
        System.out.println("当前扫描包路径为"+path);//com.luban.demo.service
        //当扫描路径应该是target下的 因为扫描的是class文件
        path = path.replace(".","/");//com/luban/demo/service文件夹路径

        //类加载器
        ClassLoader classLoader = LuBanApplicationContext.class.getClassLoader();
        //找这个资源
        URL url = classLoader.getResource(path);

        //防止中文乱码
        File file = new File(java.net.URLDecoder.decode(url.getFile(),"utf-8"));//com/luban/demo/service文件夹
        if(file.isDirectory()){
            for (File listFile : file.listFiles()) {
                String absolutePath = listFile.getAbsolutePath();
                absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
                absolutePath = absolutePath.replace("\\",".");
                //去找被扫描的类
                Class<?> clazz = classLoader.loadClass(absolutePath);
                classList.add(clazz);
            }
        }
        System.out.println(classList);
        return classList;
    }

    private void instanceSingletonBean() {
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if(beanDefinition.getScope().equals("singleton")){
                //是单例的 现在就实例化（先不管懒加载）
                if(!singletonObjectsMap.containsKey(beanName)){
                    Object bean = doCreateBean(beanName,beanDefinition);
                    singletonObjectsMap.put(beanName,bean);
                }
            }
        }
    }

    /**
     * 实例化一个对象
     * @param beanName
     * @param beanDefinition
     */
    private Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
        try {
            //1、实例化
            Class clazz = beanDefinition.getBeanClass();
            Object bean = clazz.getConstructor().newInstance();

            //2、依赖注入（属性填充）
            Field[] fields = clazz.getDeclaredFields();//得到类上的所有属性 注意这里是getDeclaredFields
            for (Field field : fields) {
                if(field.isAnnotationPresent(Autowired.class)){
                    //属性赋值
                    Object o = getBean(field.getName().toLowerCase());
                    field.setAccessible(true);
                    field.set(bean,o);//属性填充到bean中
                }
            }
            return bean;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取Bean的方法
     */
    public Object getBean(String beanName){
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition.getScope().equals("prototype")){
            //原型bean 创建
            Object bean = doCreateBean(beanName,beanDefinition);
            return bean;
        }else if(beanDefinition.getScope().equals("singleton")){
            //单例池中取(假设一定有这个bean 不做其他处理了)
            Object bean = singletonObjectsMap.get(beanName);
            if(bean == null){
                Object o = doCreateBean(beanName,beanDefinition);
                singletonObjectsMap.put(beanName,o);
                return o;
            }
            return bean;
        }
        return null;
    }
}
